package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.lkd.common.VMSystem;
import com.lkd.config.ConsulConfig;
import com.lkd.config.TopicConfig;
import com.lkd.contract.OrderCheck;
import com.lkd.contract.VendoutContract;
import com.lkd.contract.VendoutData;
import com.lkd.dao.OrderDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.UserService;
import com.lkd.feign.VMService;
import com.lkd.service.OrderService;
import com.lkd.utils.DistributedLock;
import com.lkd.vo.PartnerVO;
import com.lkd.vo.PayVO;
import com.lkd.vo.VmVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private MqttProducer mqttProducer;

    @Autowired
    VMService vmService;

    @Autowired
    UserService userService;

    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo, orderNo);
        return this.getOne(qw);
    }

    @Autowired
    ConsulConfig consulConfig;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public OrderEntity createOrder(PayVO payVO) {
        if (!vmService.hasCapacity(payVO.getInnerCode(), Long.valueOf(payVO.getSkuId()))) {
            throw new LogicException("该商品已经售空，请购买其他商品");
        }
        //分布式锁，机器同一时间只能处理一次锁
        DistributedLock lock = new DistributedLock(
                consulConfig.getConsulRegisterHost(),
                consulConfig.getConsulRegisterPort());
        DistributedLock.LockContext lockContext = lock.getLock(payVO.getInnerCode()+"_"+payVO.getSkuId(),60);
        if (!lockContext.isGetLock()){
            throw new LogicException("机器出货中请稍后再试");
        }
        redisTemplate.boundValueOps(
                VMSystem.VM_LOCK_KEY_PREF+payVO.getInnerCode()+"_"+payVO.getSkuId())
                .set(lockContext.getSession(), Duration.ofSeconds(60)); //存入redis后是为了释放

        OrderEntity orderEntity = new OrderEntity(); //创建订单对象
        orderEntity.setOpenId(payVO.getOpenId());  //设置微信用户openId
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_NOPAY); //设置支付状态为未支付
        orderEntity.setStatus(VMSystem.ORDER_STATUS_CREATE); //设置订单状态为创建订单
        orderEntity.setOrderNo(payVO.getInnerCode() + System.nanoTime()); //设置订单号

        //根据售货机编号查询售货机信息 ,并复制给订单对象
        VmVO vmInfo = vmService.getVMInfo(payVO.getInnerCode());
        BeanUtils.copyProperties(vmInfo, orderEntity);
        orderEntity.setAddr(vmInfo.getNodeAddr());  //设置点位地址

        //根据商品编号查询商品信息，并复制给订单对象
        var skuVO = vmService.getSku(payVO.getSkuId());
        BeanUtils.copyProperties(skuVO, orderEntity);
        orderEntity.setAmount(skuVO.getRealPrice()); //设置商品价格

        //计算合作商账单分账金额
        PartnerVO partner = userService.getPartner(vmInfo.getOwnerId()); //根据合作商Id获取合作商信息
        BigDecimal bigDecimal = new BigDecimal(skuVO.getRealPrice());  //获取商品的真实价格用于处理合作商的提成
        //对商品的真实价格采用算法获取合作商的分账金额
        int bill = bigDecimal //bigDecimal：商品真实价格
                .multiply(new BigDecimal(partner.getRatio()))   //商品真实价格 x 分成比例 =分成金额
                //divide(new BigDecimal(val),    val:除以相应的值
                // scale,  保留小数位数
                // RoundingMode.HALF_UP) ROUND_HALF_UP: 遇到.5的情况时往上近似,例: 1.5 ->;2
                .divide(new BigDecimal(100), 0, RoundingMode.HALF_UP) //除以100，并保留0位小数，进行四舍五入
                .intValue(); //输出int数据

        orderEntity.setBill(bill);
        this.save(orderEntity);
        //将订单放到延迟队列中，5分钟后检查支付状态！！！！！！！！！！！！！！！！！！
        OrderCheck orderCheck = new OrderCheck();
        orderCheck.setOrderNo(orderEntity.getOrderNo());
        try {
            mqttProducer.send("$delayed/300/" + TopicConfig.ORDER_CHECK_TOPIC, 2, orderCheck);
        } catch (JsonProcessingException e) {
            log.error("send to emq error", e);
        }
        return orderEntity;
    }

    @Override
    public boolean vendout(String orderNo, Long skuId, String innerCode) {
        //封装协议中的数据
        var vendoutData = new VendoutData();
        vendoutData.setOrderNo(orderNo);
        vendoutData.setSkuId(skuId);
        //封装协议
        VendoutContract vendoutContract = new VendoutContract();
        vendoutContract.setVendoutData(vendoutData);
        vendoutContract.setInnerCode(innerCode);
        //向售货机微服务  发送出货请求
        try {
            log.info("VMS_VENDOUT_TOPIC主题发送，参数：{}", vendoutContract);
            mqttProducer.send(TopicConfig.VMS_VENDOUT_TOPIC, 2, vendoutContract);
        } catch (JsonProcessingException e) {
            log.error("VMS_VENDOUT_TOPIC主题发送失败" + e);
            return false;
        }
        return true;
    }

}
